﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using GPSCrowdSource.DataStructures;
using GPSCrowdSource.Algorithms;

namespace GPSCrowdSource.DataStructures {
  
  /// <summary>
  /// Keeps track of a particular route, it's schedule and the graph that defines it.
  /// </summary>
  public class Route : List<Station> {

    #region Constructors

    /// <summary>
    /// Create a route
    /// </summary>
    public Route(eRTDLine inLine)  {
      Line = inLine;
      }

    #endregion

    #region Properties
    
    /// <summary>
    /// Get/Set the line.
    /// </summary>
    public eRTDLine Line { get; set; }

    /// <summary>
    /// Get the station at the specified index.
    /// </summary>
    public Station this[int idx] {
      get {
        lock(this) {
          return base[idx];
          }
        }
      } 

    #endregion

    /// <summary>
    /// Locate the index of the station that is closest to the given position as long
    /// as it's index is not the given index.
    /// </summary>
    private int FindClosest(GeoPosition inPos, int notIdx) {
      double min = double.MaxValue;
      int minIdx = -1;

      for(int i=0;i<Count;i++) {
        Station s = this[i];
        double d = GeoUtils.GetDistance(s,inPos);

        if(i != notIdx && d < min) {
          min = d;
          minIdx = i;
          }
        
        }

      if(minIdx != -1)
        return minIdx;

      return -1;
      }

    /// <summary>
    /// Locate the closest stations to the given position, no more than 2 stations are returned.
    /// </summary>
    /// <returns>null if no close stations were found</returns>
    public Station[] FindClosest(GeoPosition inPos) {

      List<Station> stats = new List<Station>();
      int idx1 = FindClosest(inPos,-1);
      int idx2 = FindClosest(inPos,idx1);
      
      if(idx1 != -1) stats.Add(this[idx1]);
      if(idx2 != -1) stats.Add(this[idx2]);

      return stats.ToArray();
      }

    public String ToString(eRTDDirection dir) {
      StringBuilder sb = new StringBuilder();
      
      for(int i=0;i<Count;i++) {
        if(i != 0)
          sb.Append(" ");
        sb.Append(this[i].Name);
        } 

      sb.Append(Environment.NewLine);

      
      if(Count > 0 && this[0][dir] != null && this[0][dir].Length > 0) {
        int cnt = this[0][dir].Length;
      
        for(int j=0;j<cnt;j++) {
          
          for(int i=0;i<Count;i++) {
            Station s = this[i];
            
            TimeSpan[] ts = s[dir];
            if(ts != null && j < ts.Length) {
              int hr = ts[j].Hours;
              int min = ts[j].Minutes;

              sb.Append(ts[j].ToString());
              //if(ts[j].Hours > 12)
              //  sb.Append(String.Format("{0:0#}{1:0#}P",(hr%12),min));
              //else
              //  sb.Append(String.Format("{0:0#}{1:0#}A",hr,min));

              sb.Append(" ");
              }
            }

          sb.Append(Environment.NewLine);
          }
        }
      
      return sb.ToString();
      }

    public override string ToString() {
      
      StringBuilder sb = new StringBuilder();
      foreach(eRTDDirection dir in Enum.GetValues(typeof(eRTDDirection))) {
        sb.Append(dir + "" + Line + Environment.NewLine);
        sb.Append(ToString(dir));
        sb.Append("---------------------------------------------" + Environment.NewLine);
        }

      return sb.ToString();
      }

    }

  }
